/******************************************************************
 * This program was written as part of
 *   Assignment 4
 *   Computer Graphics                                             
 *   Semester 1, 2013
 *   School of Computer Science,
 *   The University of Adelaide
 *                                                                          
 * I declare that all material in this assessment is my own work except where
 * there is clear acknowledgement and reference to the work of others. I have
 * read the University Policy Statement on Plagiarism, Collusion and Related
 * Forms of Cheating:  

 * http://www.adelaide.edu.au/policies/?230

 * I give permission for my assessment work, including my subversion
 * repository, to be reproduced and submitted to academic staff for the
 * purposes of assessment and to be copied, submitted and retained in a form
 * suitable for electronic checking of plagiarism.  
                            
 * Authors:
 *  Terry Moschou    a1208955
 *  Salih Al-Rashid  a1210108
 *  Ben   McAleer    a1212203
*******************************************************************/
#include "Skybox.hpp"

#include "Common.hpp"
#include "Scene.hpp"
#include "Context.hpp"
#include "Camera.hpp"

void setUniforms()
{
  mat4 viewMatrix = g_context.m_camera->getViewMatrix();
  mat4 projMatrix = g_context.m_camera->getProjectionMatrix();
  
  std::map<Context::ProgramId, Program*>::iterator itr;
  for (itr = g_context.m_progs.begin(); itr != g_context.m_progs.end(); ++itr) {
  
    Context::ProgramId programId = itr->first;
    if (programId == Context::FireUpdate)
      continue;
    Program * program = g_context.useProgram(programId);
    
    int ul_view = program->getUniformLocation("MatrixView");
    glUniformMatrix4fv(ul_view, 1, false,
                       &viewMatrix[0][0]);
    
    int ul_proj = program->getUniformLocation("MatrixProjection");
    glUniformMatrix4fv(ul_proj, 1, false,
                       &projMatrix[0][0]);
    
  }
  
  Program * program = g_context.useProgram(Context::Normal);
  
  int ul_lightInfo = program->getUniformLocation("Light.Position");
    
  vec4 lightPosition(0.2f, 1.0f, 1.0f, 0.0f);
  vec4 ecLightPosition = viewMatrix * lightPosition;
    
  glUniform4fv(ul_lightInfo, 1, &ecLightPosition[0]);
  
  int ul_la = program->getUniformLocation("Light.La");
  int ul_ld = program->getUniformLocation("Light.Ld");
  int ul_ls = program->getUniformLocation("Light.Ls");
  
  glUniform3f(ul_la, 0.5f, 0.5f, 0.5f);
  glUniform3f(ul_ld, 1.0f, 1.0f, 1.0f);
  glUniform3f(ul_ls, 0.5f, 0.5f, 0.5f);
  
}

void displayFunc()
{
  
 
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  setUniforms();
  
  g_context.m_scene->draw(mat4(1.0f));
  
  glutSwapBuffers();
  glFlush();
}

void instructions()
{
  printf("\nWelcome to Super Segway 64!\n");
  printf("Benjamin McAleer a1212203\n");
  printf("Salih Al-Rashid  a1210108\n");
  printf("Terry Moschou    a1208955\n");
  printf("\n");
  printf("Controls:\n");
  printf("Move the player using the A,S,D,W keys and the spacebar is jump\n");
  printf("Press E to jump onto the Segway or pick up objects\n");
  printf("E also swings equipment\n");
  printf("Press Q to jump off the Segway or drop objects\n");
  printf("Move the cursor over the screen to make the person look around\n");
  printf("Press C to change camera modes\n");
  printf("In 3rd person camera mode, using the arrow keys to change your view and J,K,L,I to move\n");
  printf("\n");
  printf("Hint:\n");
  printf("Find the magic sword near the water and swing it at the secret door to unlock the cave where the Segway is hidden\n");
}

int main(int argc, char **argv)
{
  instructions();
  glutInit(&argc, argv);
  
  
  
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
  glutInitWindowPosition(0, 0);
  glutInitWindowSize(800, 600);
  
//  glutInitContextVersion(3, 2);
//  glutInitContextProfile(GLUT_CORE_PROFILE);
  glutCreateWindow(argv[0]);
  
  // glew has a bug that requires this to be set
  //glewExperimental = GL_TRUE;
  if (glewInit()) {
    ERROR("unable to initalise GLEW ... exiting");
    return 1;
  }
  
  glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
  glEnable(GL_DEPTH_TEST);

  g_context.init();

  glutDisplayFunc(displayFunc);
  //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  
  glEnable(GL_CULL_FACE);
  glutMainLoop();
  return 0;

}